/*
 * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.voilet.interview.open.eventbus;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;

/**
 * 其实就是Handler的实现
 * 内部维护了一个 PendingPostQueue 的消息队列，在 enqueue(Subscription subscription, Object event)
 * 方法中不断从 pendingPostPool 的 ArrayList 缓存池中获取 PendingPost 添加到 PendingPostQueue 队列中，
 * 并将该 PendingPost 事件发送到 Handler 中处理。
 */
public class HandlerPoster extends Handler implements Poster {

    //存放待执行的 Post Events 的事件队列
    private final PendingPostQueue queue;
    //Post 事件在 handleMessage 中执行的最大的时间值，超过这个时间值则会抛异常
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    //标识 Handler 是否被运行起来
    private boolean handlerActive;

    protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
        super(looper);
        this.eventBus = eventBus;
        this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
        //从 pendingPostPool 的 ArrayList 缓存池中获取 PendingPost 添加到 PendingPostQueue 队列中，
        // 并将该 PendingPost 事件发送到 Handler 中处理。
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            //添加到队列中
            queue.enqueue(pendingPost);
            //标记 Handler 为活跃状态
            if (!handlerActive) {
                handlerActive = true;
                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

    /**
     * 在 handleMessage 中，通过一个 while 死循环，不断从 PendingPostQueue 中取出 PendingPost 出来执行，
     * 获取到 post 之后由 eventBus 通过该 post 查找相应的 Subscriber 处理事件。
     * @param msg
     * 退出条件
     * 获取到的 PendingPost 为 null，即是 PendingPostQueue 已经没有消息可处理。
     * 每个 PendingPost 在 Handler 中执行的时间超过了最大的执行时间。
     */
    @Override
    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            long started = SystemClock.uptimeMillis();
            while (true) {
                PendingPost pendingPost = queue.poll();
                ////如果为 null，表示队列中没有 post 事件，此时标记 Handelr 关闭，并退出 while 循环
                if (pendingPost == null) {
                    synchronized (this) {
                        // Check again, this time in synchronized
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            handlerActive = false;
                            return;
                        }
                    }
                }
                //获取到 post 之后由 eventBus 通过该 post 查找相应的 Subscriber 处理事件
                eventBus.invokeSubscriber(pendingPost);
                //计算每个事件在 handleMessage 中执行的时间
                long timeInMethod = SystemClock.uptimeMillis() - started;
                if (timeInMethod >= maxMillisInsideHandleMessage) {
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                    rescheduled = true;
                    return;
                }
            }
        } finally {
            handlerActive = rescheduled;
        }
    }
}